package io.adrainty.bolee.insurance.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.adrainty.bolee.file.feign.IFileBusinessFeign;
import io.adrainty.bolee.file.models.entity.FileEntity;
import io.adrainty.bolee.framework.commons.basic.EnableEnum;
import io.adrainty.bolee.framework.commons.basic.ResponseCode;
import io.adrainty.bolee.framework.commons.basic.ResultDTO;
import io.adrainty.bolee.framework.commons.exception.AppException;
import io.adrainty.bolee.framework.commons.user.SubjectContentUtil;
import io.adrainty.bolee.framework.commons.user.UserEntity;
import io.adrainty.bolee.framework.commons.utils.JsonUtil;
import io.adrainty.bolee.framework.commons.utils.ResultDTOUtil;
import io.adrainty.bolee.insurance.handler.InsuranceHandler;
import io.adrainty.bolee.insurance.handler.InsuranceHandlerRegistry;
import io.adrainty.bolee.insurance.models.aggregate.EarningResultDTO;
import io.adrainty.bolee.insurance.models.entity.*;
import io.adrainty.bolee.insurance.models.request.DoInsuranceDTO;
import io.adrainty.bolee.insurance.repository.IInsuranceRepository;
import io.adrainty.bolee.insurance.repository.ISearchRecordRepository;
import io.adrainty.bolee.insurance.service.IInsurancePlanService;
import io.adrainty.bolee.insurance.service.IInsuranceService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

/**
 * <p>InsuranceServiceImpl</p>
 *
 * @author AdRainty
 * @version V1.0.0
 * @description IInsuranceService
 * @since 2025/8/12 10:44:39
 */

@Service
public class InsuranceServiceImpl implements IInsuranceService {

    @Resource
    private IInsuranceRepository insuranceRepository;

    @Resource
    private IInsurancePlanService insurancePlanService;

    @Resource
    private IFileBusinessFeign fileBusinessFeign;

    @Resource
    private ISearchRecordRepository searchRecordRepository;

    @Resource
    private InsuranceHandlerRegistry handlerRegistry;

    @Resource(name = "searchRecordExecutor")
    private Executor searchRecordExecutor;

    @Override
    public IPage<InsuranceEntity> getInsurancePage(Integer pageNum, Integer pageSize, InsuranceEntity insuranceEntity) {
        IPage<InsuranceEntity> page = insuranceRepository.getInsurancePage(pageNum, pageSize, insuranceEntity);
        fillInsuranceData(page.getRecords());
        return page;
    }

    @Override
    public List<InsuranceEntity> listInsurance(InsuranceEntity insuranceEntity) {
        List<InsuranceEntity> insuranceList = insuranceRepository.listInsurance(insuranceEntity);
        fillInsuranceData(insuranceList);
        createSearchContent(insuranceList, SubjectContentUtil.getUserVO());
        return insuranceList;
    }

    @Override
    public InsuranceEntity createInsurance(InsuranceEntity insuranceEntity) {
        if (!insuranceRepository.createInsurance(insuranceEntity)) {
            throw new AppException(ResponseCode.INSURANCE_CREATE_ERROR);
        }
        return insuranceEntity;
    }

    @Override
    public Boolean updateInsurance(InsuranceEntity insuranceEntity) {
        if (insuranceEntity.getId() == null) {
            throw new AppException(ResponseCode.ILLEGAL_PARAMETER);
        }
        return insuranceRepository.updateInsurance(insuranceEntity);
    }

    @Override
    public InsuranceEntity findInsuranceDetails(Long insuranceId) {
        InsuranceEntity insurance = insuranceRepository.getInsuranceById(insuranceId);
        if (insurance == null) {
            throw new AppException(ResponseCode.ILLEGAL_PARAMETER);
        }
        fillInsuranceData(List.of(insurance));
        return insurance;
    }

    private void fillInsuranceData(List<InsuranceEntity> insuranceList) {
        if (CollUtil.isEmpty(insuranceList)) return;
        List<Long> insuranceIdList = insuranceList.stream().map(InsuranceEntity::getId).toList();
        InsuranceCoefficientEntity coefficientDTO = InsuranceCoefficientEntity.builder()
                .instanceIds(insuranceIdList.toArray(Long[]::new))
                .dataState(EnableEnum.ENABLE)
                .build();
        InsurancePlanEntity planDTO = InsurancePlanEntity.builder()
                .insuranceIds(insuranceIdList.toArray(Long[]::new))
                .dataState(EnableEnum.ENABLE)
                .build();
        InsuranceConditionEntity conditionDTO = InsuranceConditionEntity.builder()
                .insuranceIds(insuranceIdList.toArray(Long[]::new))
                .dataState(EnableEnum.ENABLE)
                .build();
        Map<Long, List<InsuranceCoefficientEntity>> coefficientEntities = insuranceRepository.findCoefficientList(coefficientDTO)
                .stream().collect(Collectors.groupingBy(InsuranceCoefficientEntity::getInsuranceId));
        Map<Long, List<InsurancePlanEntity>> planEntities = insurancePlanService.findPlanList(planDTO)
                .stream().collect(Collectors.groupingBy(InsurancePlanEntity::getInsuranceId));
        Map<Long, List<InsuranceConditionEntity>> conditionEntities = insuranceRepository.findConditionList(conditionDTO)
                .stream().collect(Collectors.groupingBy(InsuranceConditionEntity::getInsuranceId));
        ResultDTO<List<FileEntity>> resultDTO = fileBusinessFeign.findInBusinessIds(insuranceIdList);
        Map<Long, List<FileEntity>> fileEntities = ResultDTOUtil.assertResultDataNotNull(resultDTO)
                .stream().collect(Collectors.groupingBy(FileEntity::getBusinessId));
        for (InsuranceEntity insurance : insuranceList) {
            insurance.setInsurancePlanVOs(planEntities.getOrDefault(insurance.getId(), new ArrayList<>()));
            insurance.setInsuranceConditionVOs(conditionEntities.getOrDefault(insurance.getId(), new ArrayList<>()));
            insurance.setInsuranceCoefficientVOs(coefficientEntities.getOrDefault(insurance.getId(), new ArrayList<>()));
            insurance.setFileVOs(fileEntities.getOrDefault(insurance.getId(), new ArrayList<>()));
        }
    }

    /**
     * 创建搜索记录
     *
     * @param insuranceVOs 保险列表
     * @param userVO       用户信息
     */
    private void createSearchContent(List<InsuranceEntity> insuranceVOs, UserEntity userVO) {
        searchRecordExecutor.execute(() -> {
            // 构建searchRecordList
            List<SearchRecordEntity> recordList = insuranceVOs.stream().map(insuranceEntity -> {
                Map<String, Object> content = Map.of(
                        "insuranceId", insuranceEntity.getId(),
                        "insuranceName", insuranceEntity.getInsuranceName()
                );
                SearchRecordEntity build = SearchRecordEntity.builder()
                        .content(JsonUtil.toJson(content))
                        .build();
                build.setCreatedBy(String.valueOf(userVO.getId()));
                return build;
            }).toList();
            //保持记录
            searchRecordRepository.saveBatch(recordList);
        });
    }

    @Override
    public String calculatePremium(DoInsuranceDTO doInsuranceDTO) {
        InsuranceHandler handler = handlerRegistry.getHandler(doInsuranceDTO.getCheckRule());
        return handler.doPremium(doInsuranceDTO);
    }

    @Override
    public EarningResultDTO calculateEarnings(DoInsuranceDTO doInsuranceDTO) {
        InsuranceHandler handler = handlerRegistry.getHandler(doInsuranceDTO.getCheckRule());
        return handler.doEarnings(doInsuranceDTO);
    }
}
